package com.pointi.emoServerM;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.concurrent.ConcurrentLinkedQueue ;

import com.pointi.emoEngine.DSP_Feature;
import com.pointi.emoEngine.EngineData;
import com.pointi.emoEngine.VoicedFrame;
import com.pointi.emoEngine.DSP_Emotion;
import com.pointi.emoTools.EmotionPacket;
import com.pointi.emoTools.SysGuidelineData;
import com.pointi.emoTools.emoCheckList;
import com.pointi.emoTools.emoConfig;
import com.pointi.emoTools.emoLogManager;
import com.pointi.vasEngine.vasEngine;

public class ThreadTCPServer extends Thread
{
	private ConcurrentLinkedQueue<ThreadTCPServer> _TCPServer ;
	private Socket mSocket ;
	private JDBC jdbc ;
	private EngineData engineData ;

	private int n_customer_default_subtime_range = 1;
	private int containerSize = 20 ;
	private int mode ;

	public ThreadTCPServer(ConcurrentLinkedQueue<ThreadTCPServer> inTCPServer)
	{
		_TCPServer = inTCPServer ;
	}

	public void start(Socket mSocket, JDBC jdbc, EngineData engineData, SysGuidelineData sysGD, int containerSize, int mode)
	{
		this.mSocket = mSocket ;
		this.jdbc =	jdbc ;
		this.engineData = engineData ;
		this.containerSize = containerSize ;
		this.mode = mode ;
		_TCPServer.add(this) ;
		super.start();
	}

	public void run()
	{
		this.fnAnalysisEngine() ;
		System.out.println("[EM][SVR] TCPServer Thread | Removed");
		_TCPServer.remove(this) ;
	}
	
	private void fnAnalysisEngine()
	{
		BufferedInputStream bis = null ;
		BufferedOutputStream bos = null ;
		
		//____________________________________________________________________________________________________
		
		try
		{
			long ST = System.currentTimeMillis() ;
			
			System.out.println("[EM][SVR] TCPServer Thread | Start !") ;
			n_customer_default_subtime_range = jdbc.fnGetSubTimeRange() ;

			//// Ready // Voiced Frame
			VoicedFrame voicedFrame = new VoicedFrame() ;
			voicedFrame.SetSubtimeRange(n_customer_default_subtime_range) ;
			voicedFrame.InitVoicedFrame() ;

			//// Ready // I/O Stream
			bis = new BufferedInputStream(mSocket.getInputStream()) ;
			bos = new BufferedOutputStream(mSocket.getOutputStream()) ;

			//// Voice Engine Input Data //
			ArrayList<int[]> mIndex = new ArrayList<int[]>() ;
			ArrayList<double[]> mFeature = new ArrayList<double[]>() ; 
			ArrayList<int[]> validIndex = new ArrayList<int[]>() ; // for Valid Emotion Index
			ArrayList<String> mQC = new ArrayList<String>() ; // Query Container			
			
			emoConfig eCONF = new emoConfig() ;
			jdbc.fnGetSysParamEngineConfig(eCONF) ;
			eCONF.fnPrintConfig() ;
			
			int CNT = 0 ;
			int LEVEL = 4 ;
			int callkey = 0 ;
			
			System.out.println("[EM][SVR] Waiting for Streams ..") ;

			//____________________________________________________________________________________________________

			boolean loopHandler = true ;
			while (loopHandler)
			{
				// ____________________________________________________________________________________________________
				// Receive Voice Frame

				byte [] receiveBuffer = new byte [EmotionPacket.packetSize] ;
				bis.read(receiveBuffer) ;

				// Parse Receive Data
				EmotionPacket receivePacket = null ;
				try
				{
					ByteArrayInputStream bais = new ByteArrayInputStream(receiveBuffer) ;
					ObjectInputStream ois = new ObjectInputStream(bais) ;
					receivePacket = (EmotionPacket)ois.readObject() ;
				}
				catch (IOException e) { e.printStackTrace(); }
				catch (Exception e) { e.printStackTrace() ; }

				// ____________________________________________________________________________________________________
				// Feature Extraction
				
				callkey = receivePacket.getCallkey() ;
				
				DSP_Feature dsp_feature = new DSP_Feature();
				dsp_feature.ExtractFeature(receivePacket.getSample(), voicedFrame, CNT, mIndex, mFeature, mode) ;

				// ____________________________________________________________________________________________________
				// Analysis Voice Frame

				if (mode == 0 || mode == 2)
				{
					DSP_Emotion dsp_emotion = new DSP_Emotion();
					double[] RESULT = dsp_emotion.EmotionEngine(voicedFrame, receivePacket.getPacketType(), LEVEL, engineData, CNT) ;
					if (RESULT != null)
					{
						// Valid Index
						int [] tempValidIndex = new int[2] ;
						tempValidIndex[0] = CNT ;
						tempValidIndex[1] = 0 ;
						if (eCONF.AI_MIN() <= RESULT[1] && RESULT[1] <= eCONF.AI_MAX()) tempValidIndex[1] = 1 ;
						validIndex.add(tempValidIndex) ;
						
						// Emotion Packet
						receivePacket.setNeutral(RESULT[0]) ;
						receivePacket.setAnger(RESULT[1]) ;
						receivePacket.setCount(voicedFrame.getAngerCount(),voicedFrame.getNeutralCount()) ;
						double[] ENERGY = voicedFrame.getEnergy();
						double sumENERGY = 0;
						for(double E : ENERGY) { sumENERGY += E; }
						sumENERGY =(sumENERGY /(50*n_customer_default_subtime_range));
						if(sumENERGY < 0) sumENERGY=0;
						receivePacket.setEnergy(sumENERGY) ;
						voicedFrame.ClearVoicedFrame() ;
					}
					receivePacket.setResult(RESULT) ; // Set Result
					if (receivePacket.getResult() != null)
					{
						CNT ++ ;
						mQC.add(receivePacket.getQuery(String.valueOf(CNT))) ;
						if (mQC.size() >= containerSize || (receivePacket.getPacketType() == EmotionPacket._LAST_PACKET)) jdbc.fnSetResult(mQC) ;
					}
				}
				// ____________________________________________________________________________________________________
				// Send Result to EmotionClient

				bos.write(new byte[1]) ;
				bos.flush() ;
				
				if (mode == 0) jdbc.fnUpdateCheckList(emoCheckList.mCheckEngine, emoCheckList._END, Integer.valueOf(callkey)) ;
				if (receivePacket.getPacketType() == EmotionPacket._LAST_PACKET) { break ; }
			}
			System.out.println("[EE] INSERT R-Table") ;

			// ____________________________________________________________________________________________________
			// VOICE ENGINE
			
			if(mode == 1 || mode == 2)
			{
				//// Voice Engine
				vasEngine VE = new vasEngine(String.valueOf(callkey), jdbc, eCONF) ;
				jdbc.fnUpdateCheckList(emoCheckList.mCheckEngine, emoCheckList._START, Integer.valueOf(callkey)) ;
				VE.fnClustering(mIndex, mFeature) ;
				jdbc.fnUpdateCheckList(emoCheckList.mCheckEngine, emoCheckList._END, Integer.valueOf(callkey)) ;
			}

			// ____________________________________________________________________________________________________

			bis.close() ;
			bos.close() ;
			mSocket.close() ;
			
			long ET = System.currentTimeMillis() ;
			emoLogManager eLM = new emoLogManager() ;
			eLM.printTXT("", "", "", "[TCP][SVR]" + (ET - ST)) ;
		}
		catch(Exception e) { e.printStackTrace() ; }
		finally
		{
			try { mSocket.close() ; }
			catch(Exception e) { e.printStackTrace() ; }
		}		
	}
}
